package com.hzlj.position.locate.config;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.fz.common.base.exception.PubException;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.sharding.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.sharding.api.sharding.complex.ComplexKeysShardingValue;
import org.springframework.stereotype.Component;

import java.sql.Timestamp;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.hutool.core.date.DatePattern.PURE_DATE_PATTERN;

/**
 * 按周分表
 *
 * @author lifh
 **/
@Slf4j
@Component("positionShardingAlgorithm")
public class PositionShardingAlgorithm implements ComplexKeysShardingAlgorithm<Date> {

    @Override
    public Collection<String> doSharding(Collection<String> collection, ComplexKeysShardingValue<Date> complexKeysShardingValue) {
        String table = complexKeysShardingValue.getLogicTableName();
        //=,in的情况
        Collection<Date> positionTimes = complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("position_time");
        if (ObjectUtil.isNotEmpty(positionTimes)) {
            return tables(table, getWeeks(positionTimes));
        }
        //<>的情况
        Range<?> positionTimesRange = complexKeysShardingValue.getColumnNameAndRangeValuesMap().get("position_time");
        Date startTime = parsePositionTime(positionTimesRange.lowerEndpoint());
        Date endTime = parsePositionTime(positionTimesRange.upperEndpoint());
        if (endTime.compareTo(startTime) < 0) {
            throw new PubException("结束时间不能小于开始时间");
        }
        return tables(table, getWeeks(startTime, endTime));
    }

    private Collection<String> tables(String table, Set<String> weeks) {
        return weeks.stream()
                .map(e -> table + "_" + e)
                .collect(Collectors.toList());
    }


    private Set<String> getWeeks(Date startTime, Date endTime) {
        List<Date> dates = Lists.newArrayList();
        Date start = DateUtil.beginOfDay(startTime);
        Date end = DateUtil.beginOfDay(endTime);
        while (start.compareTo(end) <= 0) {
            dates.add(start);
            start = DateUtil.offset(start, DateField.DAY_OF_MONTH,1);
        }
        return getWeeks(dates);
    }

    private Set<String> getWeeks(Collection<?> dates) {
        Collection<Date> parseDates = dates.stream().map(this::parsePositionTime).collect(Collectors.toList());
        Set<String> weeks = Sets.newHashSet();
        for (Date date : parseDates) {
            weeks.add(DateUtil.format(DateUtil.beginOfWeek(date, true),PURE_DATE_PATTERN));
        }
        return weeks;
    }

    private Date parsePositionTime(Object positionTime) {
        if (ObjectUtil.isEmpty(positionTime)) {
            throw new PubException("时间不能为空");
        }
        if (positionTime instanceof String) {
            return DateUtil.parse(positionTime.toString());
        }
        if (positionTime instanceof Timestamp) {
            return new Date(((Timestamp) positionTime).getTime());
        }
        if (positionTime instanceof Date) {
            return (Date) positionTime;
        }
        throw new PubException("时间格式不能为空");
    }

    @Override
    public void init() {

    }

    @Override
    public String getType() {
        return null;
    }
}
